/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package org.yonsei.iwb.sdt.refinement.generator;

import com.hp.hpl.jena.rdf.model.Model;
import com.hp.hpl.jena.rdf.model.NodeIterator;
import com.hp.hpl.jena.rdf.model.Property;
import com.hp.hpl.jena.rdf.model.RDFNode;
import com.hp.hpl.jena.rdf.model.ResIterator;
import com.hp.hpl.jena.rdf.model.Resource;
import com.hp.hpl.jena.vocabulary.OWL;
import com.hp.hpl.jena.vocabulary.XSD;
import java.util.Enumeration;
import java.util.Hashtable;
import java.util.List;
import java.util.Vector;
import org.yonsei.iwb.sdt.datastructure.tree.BranchingType;
import org.yonsei.iwb.sdt.datastructure.DecomposeCandidate;
import org.yonsei.iwb.sdt.datastructure.DecomposeCandidateSet;
import org.yonsei.iwb.sdt.ontology.PropertyArc;
import org.yonsei.iwb.sdt.refinement.CardinalityRestrictionRefinement;
import org.yonsei.iwb.sdt.refinement.DLConstructors;
import org.yonsei.iwb.sdt.refinement.DomainRestrictionRefinement;
import org.yonsei.iwb.sdt.refinement.ExpandingHistory;
import org.yonsei.iwb.sdt.refinement.ExpandingHistorySet;
import org.yonsei.iwb.sdt.refinement.Refinement;
import org.yonsei.iwb.sdt.refinement.RefinementType;
import org.yonsei.iwb.sdt.util.UtilFunctions;

/**
 *
 * @author JDK
 */
public class DomainRestrictionRefinementMaker {

    private Model model;
    private Vector<Resource> instanceSet;
    private QuantificationRefinementMaker qrm;

    public DomainRestrictionRefinementMaker(Model model, Vector<Resource> instanceSet) {
        this.model = model;
        this.instanceSet = instanceSet;
        this.qrm = new QuantificationRefinementMaker(this.model, RefinementType.DOMAINRESTRICTION);
    }

    public DecomposeCandidateSet refinementGenerator(Property property, RDFNode standard, Vector<PropertyArc> propertyHistory, Resource datatype) {

        //property set exist 

        ResIterator resi = this.model.listResourcesWithProperty(property, (RDFNode) null);
        Vector<Resource> res = UtilFunctions.getSubjectResourceVector(resi);
        List<Resource> css = this.getSatisfiedInstanceSet(standard, res, property, datatype);
        ExpandingHistorySet ehs = this.qrm.expandingHistoryCounter(propertyHistory, css);
        DecomposeCandidateSet dcs = new DecomposeCandidateSet();

        for (int i = 0; i < ehs.size(); i++) {
            ExpandingHistory eh = ehs.get(i);
            Vector<Refinement> rset = new Vector<Refinement>();
            Refinement pref = new DomainRestrictionRefinement("", standard, this.getPrefix(datatype, true), eh, property);
            Refinement nref = new DomainRestrictionRefinement(this.getNegationOrNot(datatype), standard, this.getPrefix(datatype, false), eh, property);
            nref.setBranchingType(BranchingType.NEGATION_TYPE);


            Vector<Resource> is = eh.getInstanceSet();
            Vector<Resource> cloneSet = UtilFunctions.copyInstanceSet(instanceSet);
            for (int j = 0; j < is.size(); j++) {
                Resource result = is.get(j);
                if (this.instanceSet.contains(result)) {
                    pref.setInstanceSet(result);
                    cloneSet.remove(result);
                }
            }

            if (!cloneSet.isEmpty() && !pref.getInstanceSet().isEmpty()) {
                nref.setInstanceSet(cloneSet);
                rset.add(pref);
                rset.add(nref);
            } else {
                continue;
            }

            DecomposeCandidate dc = new DecomposeCandidate(rset, RefinementType.DOMAINRESTRICTION);
            dcs.add(dc);
        }

        return dcs;
    }
    
    
    public DecomposeCandidateSet refinementGenerator(Property property, Vector<RDFNode> standardset, Vector<PropertyArc> propertyHistory, Resource datatype) {

        //property set exist and owl:datarange case
        
        ResIterator resi = this.model.listResourcesWithProperty(property, (RDFNode) null);
        List<Resource> res = resi.toList();
        
        
        DecomposeCandidateSet dcs = new DecomposeCandidateSet();        
        
         
        Hashtable<Integer, ExpandingHistorySet> h = new Hashtable<Integer, ExpandingHistorySet>();

        for (int i = 0; i < standardset.size(); i++) {
            RDFNode object = standardset.get(i);            
            List<Resource> css = this.getSatisfiedInstanceSet(object, res, property, datatype);
            ExpandingHistorySet ehs = this.qrm.expandingHistoryCounter(propertyHistory, css);
            for (int j = 0; j < ehs.size(); j++) {
                ExpandingHistory eh = ehs.get(j);
                this.putEH(h, j, eh);
            }            
        }
        
        Enumeration<Integer> e = h.keys();
        while(e.hasMoreElements()){
            int key = e.nextElement();            
            ExpandingHistorySet ehs = h.get(key);
            Vector<Refinement> rset = new Vector<Refinement>();
            
            for (int i = 0; i < ehs.size(); i++) {
                ExpandingHistory eh = ehs.get(i);
                Refinement pref = new DomainRestrictionRefinement("", standardset.get(i), this.getPrefix(datatype, true), eh, property);                
                
                Vector<Resource> is = eh.getInstanceSet();
                Vector<Resource> cloneSet = UtilFunctions.copyInstanceSet(instanceSet);
                for (int j = 0; j < is.size(); j++) {
                    Resource result = is.get(j);
                    if (this.instanceSet.contains(result)) {
                        pref.setInstanceSet(result);
                        cloneSet.remove(result);
                    }
                }

//                if (!cloneSet.isEmpty() && !pref.getInstanceSet().isEmpty()) {
                    rset.add(pref);                    
//                } else {
//                    continue;
//                }

                
            }
            DecomposeCandidate dc = new DecomposeCandidate(rset, RefinementType.DOMAINRESTRICTION);
            dcs.add(dc);
//            dcs.printDecomposeCandidateSet();
        }        
        return dcs;
    }
    
    private void putEH(Hashtable<Integer, ExpandingHistorySet> h, int key, ExpandingHistory eh){
        if(h.keySet().contains(key)){
            h.get(key).add(eh);            
        }else{
            ExpandingHistorySet ehs = new ExpandingHistorySet();
            ehs.add(eh);
            h.put(key, ehs);
        }        
    }
        
        

    public Vector<Refinement> refinementGenerator(Property property, Vector<RDFNode> standardset, Resource datatype) {

        //owl:datarange case
        Vector<Refinement> rset = new Vector<Refinement>();
        ResIterator resi = this.model.listResourcesWithProperty(property, (RDFNode) null);
        
        Vector<Resource> res = UtilFunctions.getSubjectResourceVector(resi);
        
        Vector<Resource> cloneSet = UtilFunctions.copyInstanceSet(instanceSet);

        for (int i = 0; i < standardset.size(); i++) {
            RDFNode object = standardset.get(i);
            
            List<Resource> css = this.getSatisfiedInstanceSet(object, res, property, datatype);
            
            Refinement pref = new DomainRestrictionRefinement("",object, "==", property);
            for (int j = 0; j < css.size(); j++) {
                Resource result = css.get(j);
                
                if (this.instanceSet.contains(result)) {
                    pref.setInstanceSet(result);
                    cloneSet.remove(result);
                }
            }
            if(!pref.getInstanceSet().isEmpty()){
                rset.add(pref);
            }
        }

        if (!cloneSet.isEmpty()) {
            
            Refinement nref = new DomainRestrictionRefinement(standardset, property);
            nref.setInstanceSet(cloneSet);
            rset.add(nref);
        }

        return rset;
    }

    public Vector<Refinement> refinementGenerator(Property property, RDFNode standard, Resource datatype) {
        Vector<Refinement> rset = new Vector<Refinement>();

        ResIterator resi = this.model.listResourcesWithProperty(property, (RDFNode) null);
        List<Resource> res = resi.toList();
        List<Resource> css = this.getSatisfiedInstanceSet(standard, res, property, datatype);

        Refinement pref = new DomainRestrictionRefinement("",standard, this.getPrefix(datatype, true), property);
        Refinement nref = new DomainRestrictionRefinement(this.getNegationOrNot(datatype),standard, this.getPrefix(datatype, false), property);
        nref.setBranchingType(BranchingType.NEGATION_TYPE);
        
        Vector<Resource> cloneSet = UtilFunctions.copyInstanceSet(instanceSet);
        for (int i = 0; i < css.size(); i++) {
            Resource result = css.get(i);
            if (this.instanceSet.contains(result)) {
                pref.setInstanceSet(result);
                cloneSet.remove(result);
            }
        }

        if (!cloneSet.isEmpty()) {
            nref.setInstanceSet(cloneSet);
            rset.add(pref);
            rset.add(nref);
        } else {
            return null;
        }

        return rset;
    }
    
    private String getNegationOrNot(Resource datatype){
        String s = new String();
        if(datatype.equals(XSD.xint)){
            s = "";
        }else{
            s = DLConstructors.NEGATION;
        }
        
        return s;
    }

    private String getPrefix(Resource datatype, boolean value) {
        String s = new String();

        if (datatype.equals(XSD.xint)) {
            if(value){
                s = ">";
            }else{
                s = "<=";
            }
        } else{            
            s = "==";            
        }

        return s;
    }

    private List<Resource> getSatisfiedInstanceSet(RDFNode standard, List<Resource> res, Property p, Resource datatype) {
        List<Resource> css = new Vector();

        for(int i=0 ; i < res.size() ; i++) {
            Resource r = res.get(i);
            NodeIterator ni = this.model.listObjectsOfProperty(r, p);

            if (datatype.equals(XSD.xboolean) || datatype.equals(XSD.xstring)) {
                while (ni.hasNext()) {
                    RDFNode rn = ni.nextNode();
                    if (rn.equals(standard)) {
                        css.add(r);
                    }
                }

            } else if (datatype.equals(XSD.xint)) {
                List list = ni.toList();
                if (list.size() > standard.asLiteral().getInt()) {
                    css.add(r);
                }
            } else if (datatype.equals(XSD.xstring)) {
                while (ni.hasNext()) {
                    RDFNode rn = ni.nextNode();
                    if (rn.equals(standard)) {
                        css.add(r);
                    }
                }
            } else if (datatype.equals(OWL.DataRange)) {
                
                while (ni.hasNext()) {
                    RDFNode rn = ni.nextNode();
                    if (rn.equals(standard)) {
                        css.add(r);
                    }
                }
            }
        }

        return css;
    }
}
